package thread;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;

class MyTimerTask implements Comparable<MyTimerTask> {
    private Runnable task; // 工作任务
    private long time; // 工作时间

    public MyTimerTask(Runnable task, long delay) {
        this.task = task;
        this.time = delay + System.currentTimeMillis();
    }

    // 运行
    public void run() {
        task.run();
    }

    // 返回时间
    public long getTime() {
        return time;
    }

    @Override
    public int compareTo(MyTimerTask o) {
        // 原来的减去新加的结果是就是升序（当然不推荐背 如果忘记了测试一下就可以了）
//        return (int) -(this.time - o.time);
        return (int) (this.time - o.time);
    }
}

class MyTimer {
    // 不太建议使用列表 因为每次查看哪个任务需要执行的时候都需要重新遍历
    // private List<MyTimerTask> list = new ArrayList<>();
    private final PriorityQueue<MyTimerTask> tasksQueue = new PriorityQueue<>();

    // 为什么需要自己来锁 而不用PriorityBlockingQueue 因为这个的wait是无限的 而需求中是需要有有限时间的wait
    private final Object locker = new Object();

    public void schedule(Runnable task, long delay) {
        synchronized (locker) {
            MyTimerTask timerTask = new MyTimerTask(task, delay);
            tasksQueue.offer(timerTask);
            locker.notify(); // 通知需要更新
        }
    }

    public MyTimer() {
        this.run();
    }

    // 通过一个线程来一直判断是否需要执行
    public void run() {
        Thread t = new Thread(() -> {
            try {
                while (true) {
                    synchronized (locker) {
                        while (tasksQueue.isEmpty()) {
                            // 休眠
                            locker.wait();
                        }
                        MyTimerTask task = tasksQueue.peek();
                        long curTime = System.currentTimeMillis();
                        if (curTime >= task.getTime()) {
                            // 执行
                            task.run();
                            tasksQueue.poll();
                        } else {
                            // 等待
                            // 为什么不用 sleep 因为 sleep 是处理异常情况（不可预料） 而且它是会将整个锁一起休眠
                            locker.wait(task.getTime() - System.currentTimeMillis());
                        }
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t.start();
    }
}



public class Demo37 {
    public static void main(String[] args) {
        MyTimer timer = new MyTimer();
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 3000");
            }
        }, 3000);
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 2000");
            }
        }, 2000);
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 1000");
            }
        }, 1000);
    }
}
